﻿Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports FuncClasses
Imports System.Threading.Tasks
Imports System.Threading
Imports System.Windows.Threading

Public Class ArticleViewModel
    Implements INotifyPropertyChanged

    Private _allarticles As ObservableCollection(Of ArticlePreviewModel)
    Private _displayedarticles As ObservableCollection(Of ArticlePreviewModel)
    Private db As IDatabase
    Private _dispatcher As Windows.Threading.Dispatcher
    Private _searchpattern, _category As String
    Private _usr As User

    Public Sub New(loader As IDatabase, dispatcher As Windows.Threading.Dispatcher, usr As User)
        db = loader
        _dispatcher = dispatcher
        _searchpattern = ""
        _category = ""
        _usr = usr
        Task.Factory.StartNew(AddressOf LoadArticles)
    End Sub

    Public Property SearchPattern As String
        Get
            Return _searchpattern
        End Get
        Set(value As String)
            _searchpattern = value
            NotifyPropertyChanged("SearchPattern")
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End Set
    End Property

    Public Property XPathCategory As String
        Get
            Return _category
        End Get
        Set(value As String)
            _category = value
            NotifyPropertyChanged("XPathCategory")
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End Set
    End Property

    Public Property AllArticles As ObservableCollection(Of ArticlePreviewModel)
        Get
            Return _allarticles
        End Get
        Set(value As ObservableCollection(Of ArticlePreviewModel))
            _allarticles = value
            NotifyPropertyChanged("AllArticles")
        End Set
    End Property

    Public Property DisplayedArticles As ObservableCollection(Of ArticlePreviewModel)
        Get
            Return _displayedarticles
        End Get
        Set(value As ObservableCollection(Of ArticlePreviewModel))
            _displayedarticles = value
            NotifyPropertyChanged("DisplayedArticles")
        End Set
    End Property

    Public Sub SaveArticle(art As Article)
        db.SaveOrUpdateArticle(art, _usr)
        If _usr.CanWriteArticle Then
            Dim prev As New ArticlePreviewModel With {.ArticleID = art.ArticleID, .ArticleDescription = art.ArticleDescription, .ArticlePrice = art.ArticlePrice1, .ArticleUnit = art.ArticleUnit.Name, .Category = art.ArticleCategory}
            If AllArticles.Contains(prev) Then
                AllArticles(AllArticles.IndexOf(prev)) = prev
            Else
                AllArticles.Add(prev)
            End If
            Task.Factory.StartNew(AddressOf ApplySearchPattern)
        End If
    End Sub

#Region "Loading and Filtering"
    Private Sub LoadArticles()
        Dim temp As ObservableCollection(Of ArticlePreviewModel) = db.GetAllArticles(_usr)
        _dispatcher.BeginInvoke(DispatcherPriority.Send, Sub()
                                                             AllArticles = temp
                                                             Task.Factory.StartNew(AddressOf ApplySearchPattern)
                                                         End Sub)
    End Sub

    Private Sub ApplySearchPattern()
        Dim temp As New Collection(Of ArticlePreviewModel)
        Dim m As New Mutex
        Try
            Parallel.ForEach(AllArticles, Sub(article As ArticlePreviewModel)
                                              If article.ArticleID.ToLower.Contains(SearchPattern.ToLower) OrElse article.ArticleDescription.ToLower.Contains(SearchPattern.ToLower) Then
                                                  m.WaitOne()
                                                  temp.Add(article)
                                                  m.ReleaseMutex()
                                              End If
                                          End Sub)
        Catch : End Try
        
        Dim temp2 As New ObservableCollection(Of ArticlePreviewModel)
        Try
            Parallel.ForEach(temp, Sub(article As ArticlePreviewModel)
                                       If article.Category.ToLower.StartsWith(XPathCategory.ToLower) OrElse String.IsNullOrEmpty(XPathCategory) Then
                                           m.WaitOne()
                                           temp2.Add(article)
                                           m.ReleaseMutex()
                                       End If
                                   End Sub)
        Catch : End Try
        

        Dim sortedCo = From item In temp2 Order By item.ArticleID Ascending
        Dim output As New ObservableCollection(Of ArticlePreviewModel)
        For Each item In sortedCo
            output.Add(item)
        Next
        _dispatcher.BeginInvoke(Sub()
                                    DisplayedArticles = output
                                End Sub)
    End Sub

    Public Sub Refresh()
        Task.Factory.StartNew(AddressOf LoadArticles)
    End Sub
#End Region

    Protected Sub NotifyPropertyChanged(info As [String])
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#Region "Sorting Directions"
    Private _ArticleIDDirection As ListSortDirection = ListSortDirection.Ascending
    Private _ArticleDescrDirection As ListSortDirection = ListSortDirection.Descending
    Private _ArticlePriceDirection As ListSortDirection = ListSortDirection.Descending
    Private _ArticleUnitDirection As ListSortDirection = ListSortDirection.Descending

    Private Sub LinqToCol(sortedCo As System.Linq.IOrderedEnumerable(Of ArticlePreviewModel))
        Dim output As New ObservableCollection(Of ArticlePreviewModel)
        For Each item In sortedCo
            output.Add(item)
        Next
        DisplayedArticles = output
    End Sub

    Public Sub SortByID()
        If _ArticleIDDirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedArticles Order By item.ArticleID Ascending)
            _ArticleIDDirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedArticles Order By item.ArticleID Descending)
            _ArticleIDDirection = ListSortDirection.Descending
        End If
    End Sub

    Public Sub SortByDescription()
        If _ArticleDescrDirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedArticles Order By item.ArticleDescription Ascending)
            _ArticleDescrDirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedArticles Order By item.ArticleDescription Descending)
            _ArticleDescrDirection = ListSortDirection.Descending
        End If
    End Sub

    Public Sub SortByPrice()
        If _ArticlePriceDirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedArticles Order By item.ArticlePrice Ascending)
            _ArticlePriceDirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedArticles Order By item.ArticlePrice Descending)
            _ArticlePriceDirection = ListSortDirection.Descending
        End If
    End Sub

    Public Sub SortByUnit()
        If _ArticleUnitDirection = ListSortDirection.Descending Then
            LinqToCol(From item In DisplayedArticles Order By item.ArticleUnit Ascending)
            _ArticleUnitDirection = ListSortDirection.Ascending
        Else
            LinqToCol(From item In DisplayedArticles Order By item.ArticleUnit Descending)
            _ArticleUnitDirection = ListSortDirection.Descending
        End If
    End Sub
#End Region
End Class
